package com.prim.threadpool;

import java.util.concurrent.*;

public class DemoThreadPoolExecutor {
    public static void main(String[] args) throws InterruptedException {
        DemoThreadPoolExecutor demoThreadPoolExecutor = new DemoThreadPoolExecutor();
        demoThreadPoolExecutor.test4();
    }

    /**
     * 1. 无界队列，超出核心线程数量的线程存活时间：5s
     * 无界队列 队列永远都不会满
     */
    private void test1() throws InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5,                                          // 核心线程数
                10,                                     // 最大线程数
                5,                                         //keepAliveTime，超过核心线程数的线程，如果时间超过keepAliveTime 这个线程就会被销毁
                TimeUnit.SECONDS,                                       //keepAliveTime 的时间单位
                new LinkedBlockingDeque<>()                             //无界队列
        );
        testSubmit(threadPoolExecutor);
    }

    /**
     * 2. 理解线程池的运行原理
     * 核心线程数量5 最大数量10 队列大小3 超出核心线程数的线程存活时间是：5s
     * 指定拒绝策略
     */
    private void test2() throws InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(5),
                new RejectedExecutionHandler() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        System.out.println("有任务拒绝执行了 --> 执行拒绝策略");
                    }
                });
        testSubmit(threadPoolExecutor);
        /**
         * 预计结果：
         * 1. 5个任务直接分配线程开始执行
         * 2. 5个任务进入等待队列
         * 3. 队列不够用，临时加开5个线程来执行任务（5s没有干活就销毁掉）
         * 4. 队列和线程池都满了，剩下任务没有资源了，就拒绝执行
         * 5. 任务执行，5S后，如果无任务可执行，销毁临时创建的5个线程
         */
    }

    /**
     * 核心线程：5 最大线程：5 无界队列 超出核心线程数量的线程存活时间
     * 类似：Executors.newFixedThreadPool(5);
     */
    public void test3() throws InterruptedException {

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5,
                5,
                0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingDeque<>());
        testSubmit(threadPoolExecutor);
        //线程池线程数量为：5，超出数量的任务，其他的进入队列中等待被执行
    }

    /**
     * SynchronousQueue 实际上它不是一个真正的队列，因为它不会为队列中元素维护存储空间。
     * 它维护一组线程，这些线程在等待着把元素加入或移除队列
     * put()往队列放进去一个element以后就一直wait直到其他thread进来把这个element取走
     * take()去除并且remove掉queue里的element取不到东西它会一直存在
     */
    public void test4() throws InterruptedException {
        SynchronousQueue<String> queue = new SynchronousQueue<>();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("before put...");
                try {
                    queue.put("element");
                    System.out.println("after put...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        Thread.sleep(1000L);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000L);
                    String take = queue.take();
                    System.out.println("take:" + take);
                    System.out.println("after take...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 类似：Executors.newCachedThreadPool();
     */
    public void test5() throws InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                0,
                Integer.MAX_VALUE,
                60L,
                TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>());
        testSubmit(threadPoolExecutor);
        /**
         * 预计结果：
         * 1 线程池线程数量：30 超出数量任务，其他的进入队列中等待被执行
         * 2 所有任务执行结果，60秒后 如果无任务可执行，所有线程全部被销毁，池子大小恢复为0
         */
        Thread.sleep(60000L);
        System.out.println("60秒后。再来看线程池中的数量：" + threadPoolExecutor.getPoolSize());
    }

    public void testSubmit(ThreadPoolExecutor threadPoolExecutor) throws InterruptedException {
        for (int i = 0; i < 30; i++) {
            int n = i;
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("任务:" + n + " 开始执行");
                        Thread.sleep(6000L);
                        System.out.println("任务:" + n + " 结束执行");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            System.out.println("任务:" + i + " 提交成功");
        }
        while (true) {
            //查询线程数量 队列等待数量
            Thread.sleep(1000L);
            System.out.println(">>> 线程数量:" + threadPoolExecutor.getPoolSize());
            System.out.println(">>> 等待任务队列数量:" + threadPoolExecutor.getQueue().size());
        }
    }
}
